package com.butnet.myframe.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.butnet.myframe.hql.query.OrderBys;
import com.butnet.myframe.hql.query.PageList;
import com.butnet.myframe.hql.query.PageQuery;
import com.butnet.myframe.hql.query.Where;
import com.butnet.myframe.hql.query.Wheres;

/**
 * Dao基类
 * 
 * @author Butnet
 * @param <T>
 *            此类操作的数据对象
 */
public class BaseDao<T> extends HibernateDaoSupport implements IDao<T> {
	private static boolean debug = false;
	private String entryName = null;

	/**
	 * 如果getEntryClassName()返回null或者"" 则会取得实例父类的类名
	 * 
	 * @return
	 */
	private String getTableEntryName() {
		if(entryName==null){
			Type[] t = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments();
			if (t == null || t.length == 0)
				throw new NullPointerException("未没有到找到父类 泛型参数");
			entryName = ((Class<?>) t[0]).getName();
		}
		return entryName;
	}

	@Override
	public void delete(T t) {
		Session s = getSession();
		s.delete(getTableEntryName(), t);
		s.flush();
	}

	@Override
	public boolean delete(Serializable pk) {
		getSession().delete(getTableEntryName(), pk);
		return true;
	}

	@Override
	public boolean delete(Class<?> cls, Serializable pk) {
		String hql = "DELETE " + cls.getName() + " AS a WHERE a." + getSessionFactory().getClassMetadata(cls).getIdentifierPropertyName() + "=:id";
		Query q = getSession().createQuery(hql);
		q.setParameter("id", pk);
		if (q.executeUpdate() == 1)
			return true;
		return false;
	}

	@Override
	public int delete(Wheres ws) {
		if (ws == null)
			return -1;
		String hql = "DELETE " + getTableEntryName() + " AS model ";
		ws.setObjAsName("model");
		if (ws != null)
			hql += "WHERE " + ws.toString();
		Query q = getSession().createQuery(hql);
		ws.setParameters(q);
		return q.executeUpdate();
	}

	/**
	 * 取得一个映射的对象
	 * 
	 * @param pk
	 *            主键值
	 * @return 主键对应的对象
	 */
	@Override
	@SuppressWarnings("unchecked")
	public T get(Serializable pk) {
		return (T) getSession().get(getTableEntryName(), pk);
	}

	@Override
	public Object get(Class<?> cls, Serializable pk) {
		String hql = "FROM " + cls.getName() + " AS a WHERE a." + getSessionFactory().getClassMetadata(cls).getIdentifierPropertyName() + "=:id";
		Query q = getSession().createQuery(hql);
		q.setParameter("id", pk);
		List<?> l = q.list();
		return l.size() > 0 ? l.get(0) : null;
	}

	@SuppressWarnings("unchecked")
	@Override
	public T get(OrderBys orderBys) {
		String hql = "FROM " + getTableEntryName() + " AS a";
		if (orderBys != null) {
			orderBys.setObjAsName("a");
			hql += " " + orderBys;
		}
		Query q = getSession().createQuery(hql);
		List<?> l = q.list();
		return (T) (l.size() > 0 ? l.get(0) : null);
	}

	@Override
	public Object get(Class<?> cls, OrderBys orderBy) {
		String hql = "FROM " + cls.getName() + " AS a";
		if (orderBy != null) {
			orderBy.setObjAsName("a");
			hql += orderBy;
		}
		Query q = getSession().createQuery(hql);
		List<?> l = q.list();
		return l.size() > 0 ? l.get(0) : null;
	}

	/**
	 * 取得一个映射的对象
	 * 
	 * @param pk
	 *            主键值
	 * @return 主键对应的对象
	 */
	@Override
	public T get(Wheres wh) {
		return (T) get(wh, null);
	}

	@Override
	public Object get(Class<?> cls, Wheres wheres) {
		wheres.setObjAsName("a");
		String hql = "FROM " + cls.getName() + " AS a ";
		if (wheres != null)
			hql += " WHERE " + wheres.toString();
		Query q = getSession().createQuery(hql);
		if (wheres != null)
			wheres.setParameters(q);
		List<?> l = q.list();
		return l.size() > 0 ? l.get(0) : null;
	}

	/**
	 * 取得一个映射的对象
	 * 
	 * @param wheres
	 *            查询条件
	 * @param orderByString
	 *            排序方式
	 * @return 主键对应的对象
	 */
	@Override
	@SuppressWarnings("unchecked")
	public T get(Wheres wheres, OrderBys orderBy) {
		String asName = "m";
		Wheres root = wheres;
		if (root != null)
			root.setObjAsName(asName);
	
		String hql = "FROM " + getTableEntryName() + " AS " + (root != null ? root.getObjAsName() : asName);
		if (root != null)
			hql += " WHERE " + root.toString();
		if (orderBy != null) {
			orderBy.setObjAsName(asName);
			hql += orderBy;
		}
		Query q = getSession().createQuery(hql);
		if (root != null)
			root.setParameters(q);
		List<?> l = q.list();
		return (T) (l.size() > 0 ? l.get(0) : null);
	}

	@Override
	public Object get(Class<?> cls, Wheres wheres, OrderBys orderBy) {
		String as = "a";
		String hql = "FROM " + cls.getName() + " " + as;
		if (wheres != null) {
			wheres.setObjAsName(as);
			hql += " WHERE " + wheres.toString();
		}
		if (orderBy != null)
			hql += " " + orderBy.toString();
	
		Query q = getSession().createQuery(hql);
	
		if (wheres != null)
			wheres.setParameters(q);
		List<?> l = q.list();
		return l.size() > 0 ? l.get(0) : null;
	}

	@Override
	@SuppressWarnings("unchecked")
	public T get(String[] colNames, String[] exps, Object[] values, String[] andOrs, OrderBys orderBy) {
		List<?> l = list(colNames, exps, values, andOrs, orderBy);
		return (T) (l.size() > 0 ? l.get(0) : null);
	}

	@Override
	public Object get(Class<?> cls, String[] colNames, String[] exps, Object[] values, String[] andOrs, OrderBys orderBy) {
		String asName = "m";
		Wheres wh = new Wheres();
		Wheres root = wh;
		if (colNames != null) {
			for (int i = 0; i < colNames.length; i++) {
				Where w = new Where();
				w.setObjAsName(asName);
				w.setColName(colNames[i]);
				w.setExpression(exps[i].toUpperCase());
				w.setValue(values[i]);
				wh.setWhere(w);
				if (andOrs != null && andOrs.length > 0 && i < andOrs.length) {
					wh.setAndOr(andOrs[i].toUpperCase());
					wh.setAnother(new Wheres());
					wh = wh.getAnother();
				}
			}
		}
		if (colNames == null || colNames.length == 0)
			root = null;
	
		String hql = "FROM " + cls.getName() + " AS " + asName;
		if (root != null)
			hql += " WHERE " + root.toString();
		if (orderBy != null) {
			orderBy.setObjAsName(asName);
			hql += orderBy;
		}
		Query q = getSession().createQuery(hql);
		if (root != null)
			root.setParameters(q);
		List<?> l = q.list();
		return l.size() > 0 ? l.get(0) : null;
	}

	/**
	 * 查寻指定的分页数据
	 * 
	 * @param tName
	 *            表映射名称
	 * @return 此映射的数据
	 */
	@Override
	@SuppressWarnings("unchecked")
	public List<T> list() {
		Query q = getSession().createQuery("FROM " + getTableEntryName() + " AS m");
		return q.list();
	}
	
	@SuppressWarnings("unchecked")
	public PageList<T> pageList(int pageIndex, int pageCount){
		PageQuery pq = new PageQuery(getSession(), "FROM "+getTableEntryName());
		if (pageIndex >= 0 && pageCount >= 0)
			pq.setFirstResult(pageIndex * pageCount);
		if (pageCount > 0)
			pq.setMaxResults(pageCount);
		PageList<T> pl = new PageList<T>();
		pl.setAllCount(pq.queryCount());
		pl.setList(pq.list());
		return pl;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Object> list(Class<?> cls) {
		Query q = getSession().createQuery("FROM " + cls.getName());
		return q.list();
	}

	@Override
	@SuppressWarnings("unchecked")
	public List<T> list(OrderBys orderBy) {
		String as = "m";
		if (orderBy != null)
			orderBy.setObjAsName(as);
		Query q = getSession().createQuery("FROM " + getTableEntryName() + " AS " + as + " " + (orderBy != null ? orderBy : ""));
		return q.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Object> list(Class<?> cls, OrderBys orderBy) {
		String hql = "FROM " + cls.getName() + " AS a ";
		if (orderBy != null) {
			orderBy.setObjAsName("a");
			hql += orderBy.toString();
		}
		Query q = getSession().createQuery(hql);
		return q.list();
	}

	@SuppressWarnings("unchecked")
	public List<T> list(Wheres wheres) {
		if (wheres == null)
			return null;
		wheres.setObjAsName("model");
		String hql = "FROM " + getTableEntryName();
		hql += " AS model ";
		if (wheres != null)
			hql += "WHERE " + wheres.toString();
		Query q = getSession().createQuery(hql);
		if (wheres != null) {
			wheres.setParameters(q);
		}
		return q.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Object> list(Class<?> cls, Wheres wheres) {
		String hql = "FROM " + cls.getName() + " AS a ";
		if (wheres != null) {
			wheres.setObjAsName("a");
			hql += "WHERE " + wheres.toString();
		}
		Query q = getSession().createQuery(hql);
		if (wheres != null)
			wheres.setParameters(q);
		return q.list();
	}

	/**
	 * 查寻指定的分页数据
	 * 
	 * @param pageIndex
	 *            页索引
	 * @param pageCount
	 *            每页的记录数
	 * @return 此页的数据
	 */
	@Override
	@SuppressWarnings("unchecked")
	public List<T> list(int pageIndex, int pageCount) {
		Query q = getSession().createQuery("FROM " + getTableEntryName());
		if (pageIndex >= 0 && pageCount >= 0)
			q.setFirstResult(pageIndex * pageCount);
		if (pageCount > 0)
			q.setMaxResults(pageCount);
		return q.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Object> list(Class<?> cls, int pageIndex, int pageCount) {
		String hql = "FROM " + cls.getName() + " AS a ";
		Query q = getSession().createQuery(hql);
		if (pageCount > 0) {
			q.setMaxResults(pageCount);
		}
		if (pageCount * pageIndex >= 0)
			q.setFirstResult(pageCount * pageIndex);
		return q.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> list(int pageIndex, int pageCount, int thisPageCount) {
		Query q = getSession().createQuery("FROM " + getTableEntryName());
		if (pageIndex >= 0 && pageCount >= 0)
			q.setFirstResult(pageIndex * pageCount);
		if (thisPageCount > 0)
			q.setMaxResults(thisPageCount);
		return q.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Object> list(Class<?> cls, int pageIndex, int pageCount, int thisPageCount) {
		String hql = "FROM " + cls.getName() + " AS a ";
		Query q = getSession().createQuery(hql);
		if (thisPageCount > 0) {
			q.setMaxResults(thisPageCount);
		}
		if (pageCount * pageIndex >= 0)
			q.setFirstResult(pageCount * pageIndex);
		return q.list();
	}

	/**
	 * 查寻指定的分页数据
	 * 
	 * @param pageIndex
	 *            页索引
	 * @param pageCount
	 *            每页的记录数
	 * @return 此页的数据
	 */
	@Override
	@SuppressWarnings("unchecked")
	public List<T> list(int pageIndex, int pageCount, OrderBys bys) {
		String asName = "m";
		if (bys != null)
			bys.setObjAsName(asName);
		Query q = getSession().createQuery("FROM " + getTableEntryName() + " AS " + asName + (bys == null ? "" : bys));
		if (pageIndex >= 0 && pageCount >= 0)
			q.setFirstResult(pageIndex * pageCount);
		if (pageCount > 0)
			q.setMaxResults(pageCount);
		return q.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Object> list(Class<?> cls, int pageIndex, int pageCount, OrderBys bys) {
		String hql = "FROM " + cls.getName() + " AS a ";
		if (bys != null) {
			bys.setObjAsName("a");
			hql += bys.toString();
		}
		Query q = getSession().createQuery(hql);
		if (pageCount > 0) {
			q.setMaxResults(pageCount);
		}
		if (pageCount * pageIndex >= 0)
			q.setFirstResult(pageCount * pageIndex);
		return q.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> list(int pageIndex, int pageCount, int thisPageCount, OrderBys bys) {
		String asName = "m";
		if (bys != null)
			bys.setObjAsName(asName);
		Query q = getSession().createQuery("FROM " + getTableEntryName() + " AS " + asName + (bys == null ? "" : bys));
		if (pageIndex >= 0 && pageCount >= 0)
			q.setFirstResult(pageIndex * pageCount);
		if (thisPageCount > 0)
			q.setMaxResults(thisPageCount);
		return q.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Object> list(Class<?> cls, int pageIndex, int pageCount, int thisPageCount, OrderBys bys) {
		String hql = "FROM " + cls.getName() + " AS a ";
		if (bys != null) {
			bys.setObjAsName("a");
			hql += bys.toString();
		}
		Query q = getSession().createQuery(hql);
		if (thisPageCount > 0) {
			q.setMaxResults(thisPageCount);
		}
		if (pageCount * pageIndex >= 0)
			q.setFirstResult(pageCount * pageIndex);
		return q.list();
	}

	/**
	 * 查寻数据
	 * 
	 * @param asName
	 *            AS名称
	 * @param wheres
	 *            查寻条件
	 * @param orderByStr
	 *            排序方式
	 * @return 数据链表
	 */
	@Override
	@SuppressWarnings("unchecked")
	public List<T> list(Wheres wheres, OrderBys orderBy) {
		String asName = "m";
		Wheres root = wheres;
		if (root != null)
			root.setObjAsName(asName);

		String hql = "FROM " + getTableEntryName() + " AS " + (root != null ? root.getObjAsName() : asName);
		if (root != null)
			hql += " WHERE " + root.toString();
		if (orderBy != null) {
			orderBy.setObjAsName(asName);
			hql += orderBy;
		}
		if (debug)
			System.out.println("Base.list HQL: " + hql);
		Query q = getSession().createQuery(hql);
		if (root != null)
			root.setParameters(q);
		return q.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Object> list(Class<?> cls, Wheres wheres, OrderBys orderBy) {
		String hql = "FROM " + cls.getName() + " AS a ";
		if (wheres != null) {
			wheres.setObjAsName("a");
			hql += "WHERE " + wheres.toString();
		}
		if (orderBy != null) {
			orderBy.setObjAsName("a");
			hql += " " + orderBy.toString();
		}
		Query q = getSession().createQuery(hql);
		if (wheres != null)
			wheres.setParameters(q);
		return q.list();
	}

	/**
	 * 查寻数据
	 * 
	 * @param asName
	 *            AS名称
	 * @param cols
	 *            列名字
	 * @param exps
	 *            列的运算表达式
	 * @param values
	 *            列对应的值
	 * @param andOrs
	 *            条件关系
	 * @param orderByStr
	 *            排序
	 * @return 数据链表
	 */
	@Override
	@SuppressWarnings("unchecked")
	public List<T> list(String[] cols, String[] exps, Object[] values, String[] andOrs, OrderBys orderBy) {
		String asName = "m";
		Wheres wh = new Wheres();
		Wheres root = wh;
		if (cols != null) {
			for (int i = 0; i < cols.length; i++) {
				Where w = new Where();
				w.setObjAsName(asName);
				w.setColName(cols[i]);
				w.setExpression(exps[i].toUpperCase());
				w.setValue(values[i]);
				wh.setWhere(w);
				if (andOrs != null && andOrs.length > 0 && i < andOrs.length) {
					wh.setAndOr(andOrs[i].toUpperCase());
					wh.setAnother(new Wheres());
					wh = wh.getAnother();
				}
			}
		}
		if (cols == null || cols.length == 0)
			root = null;

		String hql = "FROM " + getTableEntryName() + " AS " + asName;
		if (root != null)
			hql += " WHERE " + root.toString();
		if (orderBy != null) {
			orderBy.setObjAsName(asName);
			hql += orderBy;
		}
		Query q = getSession().createQuery(hql);
		if (root != null)
			root.setParameters(q);
		return q.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Object> list(Class<?> cls, String[] cols, String[] exps, Object[] values, String[] andOrs, OrderBys orderBy) {
		String asName = "m";
		Wheres wh = new Wheres();
		Wheres root = wh;
		if (cols != null) {
			for (int i = 0; i < cols.length; i++) {
				Where w = new Where();
				w.setObjAsName(asName);
				w.setColName(cols[i]);
				w.setExpression(exps[i].toUpperCase());
				w.setValue(values[i]);
				wh.setWhere(w);
				if (andOrs != null && andOrs.length > 0 && i < andOrs.length) {
					wh.setAndOr(andOrs[i].toUpperCase());
					wh.setAnother(new Wheres());
					wh = wh.getAnother();
				}
			}
		}
		if (cols == null || cols.length == 0)
			root = null;
	
		String hql = "FROM " + cls.getName() + " AS " + asName;
		if (root != null)
			hql += " WHERE " + root.toString();
		if (orderBy != null) {
			orderBy.setObjAsName(asName);
			hql += orderBy;
		}
		Query q = getSession().createQuery(hql);
		if (root != null)
			root.setParameters(q);
		return q.list();
	}

	@Override
	public void insert(T t) {
		Session s = getSession();
		s.save(getTableEntryName(), t);
		s.flush();
	}

	@Override
	public void insertOrUpdate(T t) {
		Session s = getSession();
		s.saveOrUpdate(getTableEntryName(), t);
		s.flush();
	}

	@Override
	public void update(T t) {
		Session s = getSession();
		s.update(getTableEntryName(), t);
		s.flush();
	}

	public int update(String[] colNames, Object[] values, Wheres wheres) {
		if (wheres == null)
			return -1;
		String asName = "model";
		String hql = "UPDATE " + getTableEntryName() + " AS " + asName + " SET ";
		List<String> args = new ArrayList<String>(colNames.length);
		String temp = null;
		for (int i = 0; i < colNames.length; i++) {
			temp = Where.argName();
			args.add(temp);
			hql += asName + "." + colNames[i] + "=:" + temp;
			if (i < colNames.length - 1)
				hql += ",";
		}
		if (wheres != null) {
			wheres.setObjAsName(asName);
			hql += " WHERE " + wheres.toString();
		}
		if (debug)
			System.out.println("DEBUG: " + hql);
		Query q = getSession().createQuery(hql);
		for (int i = 0, len = args.size(); i < len; i++) {
			q.setParameter(args.get(i), values[i]);
		}
		wheres.setParameters(q);

		return q.executeUpdate();
	}

	@Override
	public int update(Class<?> cls, String[] colNames, Object[] values, Wheres wheres) {
		if (wheres == null)
			return -1;
		String asName = "model";
		String hql = "UPDATE " + cls.getName() + " AS " + asName + " SET ";
		List<String> args = new ArrayList<String>(colNames.length);
		String temp = null;
		for (int i = 0; i < colNames.length; i++) {
			temp = Where.argName();
			args.add(temp);
			hql += asName + "." + colNames[i] + "=:" + temp;
			if (i < colNames.length - 1)
				hql += ",";
		}
		if (wheres != null) {
			wheres.setObjAsName(asName);
			hql += " WHERE " + wheres.toString();
		}
		if (debug)
			System.out.println("DEBUG: " + hql);
		Query q = getSession().createQuery(hql);
		for (int i = 0, len = args.size(); i < len; i++) {
			q.setParameter(args.get(i), values[i]);
		}
		wheres.setParameters(q);
	
		return q.executeUpdate();
	}

	@Override
	public void merge(T t) {
		getSession().merge(t);
	}

	public boolean isDebug() {
		return debug;
	}

	public void setDebug(boolean debug) {
		BaseDao.debug = debug;
	}

	@Override
	public Object exceHQL(String hql) {
		Query q = getSession().createQuery(hql);
		List<?> l = q.list();
		return l.size()>0?l.get(0):null;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Object> listHQL(String hql) {
		Query q = getSession().createQuery(hql);
		return q.list();
	}

	@Override
	public int updateHQL(String hql) {
		Query q = getSession().createQuery(hql);
		return q.executeUpdate();
	}
}
